package com.xjc.infra.util;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.jms.TextMessage;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.activemq.command.ActiveMQTextMessage;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import com.xjc.infra.entity.SessionContext;
import com.xjc.infra.entity.service.XGenericReponseDTO;
import com.xjc.infra.entity.service.XGenericRequestDTO;


/**
 * 
 * @class com.ifs.infra.interceptor.LoggerUtil
 *
 * @date 2016年6月15日
 * @author lqf
 *
 */
@Service
public class LoggerUtil {
	
	private Logger logger = Logger.getLogger(LoggerUtil.class);
    private String format = "yyyy-MM-dd HH:mm:ss SSS";
    
	/**
	 * 记录请求报文日志
	 * @param requestDTO
	 * @param absoluteMethodName
	 * @date 2016年6月15日
	 * @author lqf
	 * @throws Exception 
	 */
    public void logInit(XGenericRequestDTO requestDTO, String absoluteMethodName) throws Exception{
    	if(null==requestDTO || absoluteMethodName==null){
			throw new Exception();
    	}
            
        // 记录请求报文
        storeRequestDTO(requestDTO,absoluteMethodName);
    }

    /**
     * 记录请求报文日志（通用）
     * 适用于非正常请求DTO传参，或者多参数请求时。
     * @param params
     * @param absoluteMethodName
     * @date 2016年7月26日
     * @author lqf
     * @throws Exception 
     */
    public void logInit(Object[] params, String absoluteMethodName) throws Exception{
    	if(absoluteMethodName==null){
			throw new Exception();
    	}
		// 记录请求报文
		storeRequestDTO(params,absoluteMethodName);
    	
    }
    
    
    /**
     * 记录响应报文日志
     * @param responseDTO
     * @param sessionContext
     * @param absoluteMethodName
     * @param startMillis
     * @date 2016年6月15日
     * @author lqf
     */
    public void logEnd(XGenericReponseDTO responseDTO,SessionContext sessionContext, String absoluteMethodName, Long startMillis){
        //begin modify dengxq  2017-02-21 增加结束日志指标项
    	Long currentMillis = System.currentTimeMillis();
        Long elapsedTime = currentMillis - startMillis;         
        // 记录响应报文
        StringBuffer buffer = new StringBuffer();        
        if(logger.isInfoEnabled())
    	{
          buffer.append("[Peng-End "+ absoluteMethodName +"  "+new SimpleDateFormat(format).format(new Date()) +" ]");
      	  buffer.append(" SessionContext:"+JsonUtils.nonEmptyMapper().toJson(sessionContext));
      	  buffer.append(" Indicator :"+"{startDate:'"+new SimpleDateFormat(format).format(new Date(startMillis))+"',endDate:'"+new SimpleDateFormat(format).format(new Date(currentMillis))+"',RT:"+elapsedTime+"}");
      	  if(responseDTO!=null)
      	  {
      	    buffer.append(" Rets:"+JsonUtils.nonEmptyMapper().toJson(responseDTO.getTransactionStatus()));
      	  }
    	}
    	
    	if(logger.isDebugEnabled()){
    		buffer.append(" Rets:" + JsonUtils.nonEmptyMapper().toJson(responseDTO));
    	}
    	//End modify dengxq 2017-02-21 增加结束日志指标项
    	logger.info(buffer);
    }
    
    /**
     * 记录响应报文
     * @param responseObj  取值TransactionStatus、ModelAndView等对象
     * @param sessionContext
     * @param absoluteMethodName
     * @param startMillis
     * @date 2016年6月16日
     * @author lqf
     */
    public void logEnd(Object responseObj,SessionContext sessionContext, String absoluteMethodName, Long startMillis){    	
        Long currentMillis = System.currentTimeMillis();
        Long elapsedTime = currentMillis - startMillis;
    	StringBuffer buffer = new StringBuffer();
    	//Begin modify dengxq 2017-02-21 增加结束日志指标项
    	if(logger.isInfoEnabled())
    	{
    	  buffer.append("[Peng-End "+ absoluteMethodName +"  "+new SimpleDateFormat(format).format(new Date()) +" ]");
    	  buffer.append(" SessionContext:"+JsonUtils.nonEmptyMapper().toJson(sessionContext));
    	  buffer.append(" Indicator :{startDate:'"+new SimpleDateFormat(format).format(new Date(startMillis))+"',endDate:'"+new SimpleDateFormat(format).format(new Date(currentMillis))+"',RT:"+elapsedTime+"}");    	 
    	  buffer.append(" Rets:null");
    	}
    	
    	if(logger.isDebugEnabled()){
    		buffer.append(" Rets:" + JsonUtils.nonEmptyMapper().toJson(responseObj));
    	}
    	//End modify dengxq 2017-02-21 增加结束日志指标项
    	logger.info(buffer);
    }
    
    /**
     * 记录错误日志（通用）
     * 适用于非正常请求DTO传参，或者多参数请求时。
     * @param requestObjs 请求参数数组
     * @param sessionContext 请求sessionContext
     * @param absoluteMethodName 请求方法
     * @param e
     * @date 2016年6月15日
     * @author lqf
     */
    public void logError(Object[] requestObjs,SessionContext sessionContext, String absoluteMethodName,Throwable e){
        // 记录错误
    	storeErrorLog(requestObjs,sessionContext,absoluteMethodName,e);
    }
    
    /**
     * 记录错误日志
     * @param requestDTO
     * @param absoluteMethodName
     * @param e
     * @date 2016年6月15日
     * @author lqf
     */
    public void logError(XGenericRequestDTO requestDTO, String absoluteMethodName,Throwable e){
        // 记录错误
        storeErrorLog(requestDTO,absoluteMethodName,e);
    }
    
    /**
     * 记录错误日志
     * @param param
     * @param sessionContext
     * @param absoluteMethodName
     * @param e
     */
    public void logError(Object param,SessionContext sessionContext, String absoluteMethodName,Throwable e){
        // 判断日志级别是否高于error如果高于error则不记录系统日志。
        storeErrorLog(param, sessionContext, absoluteMethodName, e);
    }
    /**
     * 记录debug日志  主要用于用户自定义调试 
     * @param absoluteMethodName
     * @param debugInfo
     */
    public void logDebug(String absoluteMethodName,String debugInfo){
    	if(logger.isDebugEnabled()){
    		logger.debug("[Peng-Debug "+absoluteMethodName +"  "+new SimpleDateFormat(format).format(new Date()) +"] "+debugInfo);
    	}
    }
    
    /**
     * 记录请求报文
     * @param requestDTO
     * @param absoluteMethodName
     * @date 2016年6月15日
     * @author lqf
     * @throws IOException 
     */
    private void storeRequestDTO(XGenericRequestDTO requestDTO,String absoluteMethodName){
    	if(logger.isInfoEnabled()){
    		logger.info("[Peng-Init "+ absoluteMethodName +"  "+new SimpleDateFormat(format).format(new Date()) +" ]"
            		+ " SessionContext:"+JsonUtils.nonEmptyMapper().toJson(requestDTO.getSessionContext())
            		+ " Args:" + JsonUtils.nonEmptyMapper().toJson(requestDTO));
    	}
    }
    
    /**
    * 记录请求报文
    * @param absoluteMethodName
    * @param sessionContextJson
    * @param paramsJson
    * @date 2016年7月26日
    * @author lqf
    */
   private void storeRequestDTO(String absoluteMethodName,String sessionContextJson,String paramsJson){
	   if(logger.isInfoEnabled()){
		   logger.info("[Peng-Init "+ absoluteMethodName  +"  "+new SimpleDateFormat(format).format(new Date()) +" ]"
				   	+" SessionContext:" + sessionContextJson
				   	+" Args:" + paramsJson);  
	   }
   }
   
   /**
    * 记录业务错误日志
    * @param sessionContext
    * @param absoluteMethodName
    * @param errorMsg
    */
   public void logError(SessionContext sessionContext, String absoluteMethodName,String errorMsg){
	   //Begin add by dengxq 2016/11/24 修改成统一的JSON转换类
	   logger.error("[Peng-Error "+ absoluteMethodName  +"  "+new SimpleDateFormat(format).format(new Date()) +" ]"
    			+ " SessionContext:"+JsonUtils.nonEmptyMapper().toJson(sessionContext)
    			+ " error :" + errorMsg);
	   //End add by dengxq 2016/11/24 修改成统一的JSON转换类
   }
   
   /**
    * 记录业务info日志
    * @param sessionContext
    * @param absoluteMethodName
    * @param errorMsg
    */
   public void logInfo(SessionContext sessionContext, String absoluteMethodName,String errorMsg){
	  if(logger.isInfoEnabled()){
		  //Begin add by dengxq 2016/11/24 修改成统一的JSON转换类
		  logger.info("[Peng-Info "+ absoluteMethodName  +"  "+new SimpleDateFormat(format).format(new Date()) +" ]"
	    			+ " SessionContext:"+JsonUtils.nonEmptyMapper().toJson(sessionContext));
		  //End add by dengxq 2016/11/24 修改成统一的JSON转换类 
	  }
	  if(logger.isDebugEnabled()){
		  logger.debug(" info :" + errorMsg);
	  }
  }
   
   
   /**
    * 记录多参数访问时请求报文日志 
    * @param params 参数数组
    * @param absoluteMethodName 调用方法名
    * @date 2016年7月26日
    * @author lqf
    */
   private  void storeRequestDTO(Object[] params,String absoluteMethodName){
	   	String sessionContext = null ; 
	   	if(params==null){
	   		storeRequestDTO(absoluteMethodName, null, null);
	       	return ;
	   	}
	   	for (int i = 0; i < params.length; i++) {
			Object object = params[i];
			if(null==object){
				continue;
			}
			if(object instanceof XGenericRequestDTO ){
				sessionContext = JsonUtils.nonEmptyMapper().toJson(((XGenericRequestDTO)object).getSessionContext());
				break;
			}else if( object instanceof SessionContext ){
				sessionContext = JsonUtils.nonEmptyMapper().toJson(object);
				break;
			}
			else if(object instanceof ActiveMQTextMessage)
			{
				try {
					TextMessage  message =(TextMessage)object;					
					XGenericRequestDTO req = (XGenericRequestDTO)JsonUtil.fromJson(message.getText(), XGenericRequestDTO.class);	
					sessionContext =  JsonUtils.nonEmptyMapper().toJson(req.getSessionContext());
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	   	storeRequestDTO(absoluteMethodName, sessionContext, parseParamsToJson(params));
   }
   
   
   /**
    * 解析参数数组为json字符串
    * 去掉部分参数的解释 如HttpSession、HttpSession、HttpServletResponse等
    * 该方法针对flow和portal端用
    * @param params
    * @return
    * @date 2016年7月26日
    * @author lqf
    */
   private String parseParamsToJson(Object[] params){
	   	StringBuffer args = new StringBuffer();
	   	if(params==null){
	       	return null;
	   	}
	   	for (int i = 0; i < params.length; i++) {
			Object object = params[i];
			if(null==object){
				continue;
			}
			if(object instanceof HttpSession || object instanceof HttpServletRequest ||object instanceof HttpServletResponse ){
				continue;
			}
			else if(object instanceof ActiveMQTextMessage)
			{
				try {
					TextMessage  message =(TextMessage)object;	
					String clazz = object.getClass().getName().substring(object.getClass().getName().lastIndexOf(".")+1);
					args.append(clazz).append(":").append(message.getText()).append(",");					
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			else {
				String clazz = object.getClass().getName().substring(object.getClass().getName().lastIndexOf(".")+1);
				args.append(clazz).append(":").append(JsonUtils.nonEmptyMapper().toJson(object)).append(",");
			}
		}
	   	if(args.lastIndexOf(",")>0){
	   		args.delete(args.lastIndexOf(","), args.length());
	   	}
	   	args.insert(0, "{").append("}");
	   	return args.toString();
   }

    /**
     * 记录相应报文
     * @param responseDTO
     * @param sessionContext
     * @param absoluteMethodName
     * @date 2016年6月15日
     * @author lqf
     * @throws IOException 
     */
    private void storeResponseDTO(Object responseObj,SessionContext sessionContext,String absoluteMethodName){
    	if(logger.isInfoEnabled()){
    		logger.info("[Peng-End "+ absoluteMethodName +"  "+new SimpleDateFormat(format).format(new Date()) +" ]"
        			+ " SessionContext:"+JsonUtils.nonEmptyMapper().toJson(sessionContext));
    	}
    	if(logger.isDebugEnabled()){
    		logger.debug(" Rets:" + JsonUtils.nonEmptyMapper().toJson(responseObj));
    	}
    }

    /**
     * 记录错误日志
     * @param requestDTO
     * @param absoluteMethodName
     * @date 2016年6月15日
     * @author lqf
     * @throws IOException 
     */
    private void storeErrorLog(XGenericRequestDTO requestDTO,String absoluteMethodName,Throwable e){
        logger.error("[Peng-Error "+ absoluteMethodName +"  "+new SimpleDateFormat(format).format(new Date()) + " ]"
        		+ " SessionContext:"+JsonUtils.nonEmptyMapper().toJson(requestDTO.getSessionContext())
        		+ " Args:" + JsonUtils.nonEmptyMapper().toJson(requestDTO)
        		+ " error :" + getStackTrace(e));
    }
    
    /**
     *  记录错误日志
     * @param requestDTO
     * @param params
     * @param absoluteMethodName
     * @param e
     * @date 2016年6月16日
     * @author lqf
     */
     private void storeErrorLog(Object[] requestObj,SessionContext sessionContext,String absoluteMethodName,Throwable e){
         logger.error("[Peng-Error "+ absoluteMethodName  +"  "+new SimpleDateFormat(format).format(new Date()) +" ]"
         		+ " SessionContext:"+JsonUtils.nonEmptyMapper().toJson(sessionContext)
         		+ " Args:" + parseParamsToJson(requestObj)
         		+ " error :" + getStackTrace(e));
     }
     
     /**
      * 记录错误日志
      * @param param
      * @param sessionContext
      * @param absoluteMethodName
      * @param e
      */
     private void storeErrorLog(Object param,SessionContext sessionContext,String absoluteMethodName,Throwable e){
         logger.error("[Peng-Error "+ absoluteMethodName  +"  "+new SimpleDateFormat(format).format(new Date()) +" ]"
         		+ " SessionContext:"+JsonUtils.nonEmptyMapper().toJson(sessionContext)
         		+ " Args:" + JsonUtils.nonEmptyMapper().toJson(param)
         		+ " error :" + getStackTrace(e));
     }
     
    /**
     * 获取异常堆栈信息
     * @param t
     * @return
     */
	private  String getStackTrace(Throwable t) {
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		try {
			t.printStackTrace(pw);
			return sw.toString();
		} finally {
			pw.close();
		}
	}
    
}
